using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

namespace Boggle.Net.Model
{
    public sealed class WordFinder
    {
        private readonly List<Tray.Location> _searchPath = new List<Tray.Location>(Tray.Capacity);

        private readonly Tray _tray;
        private readonly IWordList _wordList;

        public WordFinder(Tray tray, IWordList wordList)
        {
            Contract.Requires<ArgumentNullException>(tray != null);
            Contract.Requires<ArgumentNullException>(wordList != null);

            _wordList = wordList;
            _tray = tray;
        }

        public IEnumerable<SearchResult> WordsFoundStartingAt(Tray.Location location)
        {
            Contract.Requires<ArgumentNullException>(location != null);
            return WordsFoundEndingAt(location);
        }

        private IEnumerable<SearchResult> WordsFoundEndingAt(Tray.Location location)
        {
            _searchPath.Add(location);

            var word = String.Concat(_searchPath.Select(searchLocation => _tray.LettersAt(searchLocation)));

            if (word.Length >= Game.MinimumWordLength && _wordList.ContainsWord(word))
            {
                yield return new SearchResult(_searchPath.ToArray(), word);
            }

            if (_searchPath.Count < Tray.Capacity && _wordList.ContainsWordStartingWith(word))
            {
                foreach (var result in location.NeighbouringLocations.Except(_searchPath).SelectMany(WordsFoundEndingAt))
                    yield return result;
            }

            // Pop location
            _searchPath.RemoveAt(_searchPath.Count - 1);
        }
    }
}